#pragma warning(disable:4996)
#include "ZlDoorControlBoard.h"

#include <sstream>

#include "CDeviceManager.h"
#include "zlbase/zlbase.h"

int32_t ZLDcbGetBoxCount()
{
    return CDeviceManager::Instance().GetBoxCount();
}

int32_t ZLDcbGetFirmwareVersion(char *version)
{
    std::ostringstream oss;
    auto devices = CDeviceManager::Instance().GetDoorControlBoardList();
    
    for (const auto &d : devices)
    {
        oss << d.second->GetNumber() << ":";

        char tmp[256] {0x00};
        auto ret = d.second->GetFirmwareVersion(tmp);
        if (ret != zl::zlbase::ZLResult_Success)
        {
            oss << std::string("error;");
        }
        else
        {
            oss << tmp << ";";
        }
    }

    if (oss.str().size() <= 0)
    {
        return zl::zlbase::ZLResult_Fail;
    }

    strncpy(version, oss.str().c_str(), oss.str().size() - 1);
    return zl::zlbase::ZLResult_Success;
}

int32_t ZLDcbOpenLocker(int32_t boxnum)
{
    auto devices_config = CDeviceManager::Instance().GetDevicesConfig();
    auto devices = CDeviceManager::Instance().GetDoorControlBoardList();

    if(devices_config.empty())
    {
        return zl::zlbase::ZLResult_Unconnected;
    }

    int32_t index = boxnum;
    for (const auto &dc : devices_config)
    {
        if (index > dc.count)
        {
            index -= dc.count;
            continue;
        }

        auto device = devices[dc.number];
        if (device == nullptr)
        {
            return zl::zlbase::ZLResult_Unconnected;
        }
        return device->OpenLocker(index);
    }
}

int32_t ZLDcbOpenLockerStatus(int32_t boxnum, unsigned char *status)
{
    auto devices_config = CDeviceManager::Instance().GetDevicesConfig();
    auto devices = CDeviceManager::Instance().GetDoorControlBoardList();

    if(devices_config.empty())
    {
        return zl::zlbase::ZLResult_Unconnected;
    }

    int32_t index = boxnum;
    for (const auto &dc : devices_config)
    {
        if (index > dc.count)
        {
            index -= dc.count;
            continue;
        }

        auto device = devices[dc.number];
        if (device == nullptr)
        {
            return zl::zlbase::ZLResult_Unconnected;
        }
        return device->OpenLocker(index, *status);
    }
}

int32_t ZLDcbGetAllDoorStatus(unsigned char *status, size_t *len)
{
    auto devices = CDeviceManager::Instance().GetDoorControlBoardList();
    auto devices_config = CDeviceManager::Instance().GetDevicesConfig();

    if(devices_config.empty())
    {
        return zl::zlbase::ZLResult_Unconnected;
    }

    size_t count = 0;
    for (const auto &dc : devices_config)
    {
        auto d = devices[dc.number];

        unsigned char tmp[256] {0x00};
        size_t tmp_len = 256;
        if (devices[dc.number] != nullptr)
        {
            auto ret = d->GetDoorStatus(tmp, tmp_len);
            if (ret != zl::zlbase::ZLResult_Success)
            {
                for (int i = 0; i < dc.count; ++i)
                {
                    tmp[i] = 0x02;
                }
            }
        }

        auto t1 = count + dc.count > *len ? *len - count : dc.count;
        for (size_t i = 0; i < t1; ++i)
        {
            status[count + i] = tmp[i];
        }
        count += t1;
    }
    *len = count;
    return zl::zlbase::ZLResult_Success;
}

int32_t ZLDcbGetDoorStatus(int32_t boxnum, unsigned char *status)
{
    auto devices_config = CDeviceManager::Instance().GetDevicesConfig();
    auto devices = CDeviceManager::Instance().GetDoorControlBoardList();

    if(devices_config.empty())
    {
        return zl::zlbase::ZLResult_Unconnected;
    }

    int32_t index = boxnum;
    for (const auto &dc : devices_config)
    {
        if (index > dc.count)
        {
            index -= dc.count;
            continue;
        }

        auto device = devices[dc.number];
        if (device == nullptr)
        {
            return zl::zlbase::ZLResult_Unconnected;
        }
        return device->GetDoorStatus(index, *status);
    }
}

int32_t ZLDcbGetAllItemStatus(unsigned char *status, size_t *len)
{
    auto devices = CDeviceManager::Instance().GetDoorControlBoardList();
    auto devices_config = CDeviceManager::Instance().GetDevicesConfig();

    if(devices_config.empty())
    {
        return zl::zlbase::ZLResult_Unconnected;
    }

    size_t count = 0;
    for (const auto &dc : devices_config)
    {
        unsigned char tmp[256] {0x00};
        size_t tmp_len = 256;

        auto device = devices[dc.number];
        if (device != nullptr)
        {
            auto ret = device->GetItemStatus(tmp, tmp_len);
            if (ret != zl::zlbase::ZLResult_Success)
            {
                for (int i = 0; i < dc.count; ++i)
                {
                    tmp[i] = 0x02;
                }
            }
        }

        auto t1 = count + dc.count > *len ? *len - count : dc.count;
        for (size_t i = 0; i < t1; ++i)
        {
            status[count + i] = tmp[i];
        }
        count += t1;
    }
    *len = count;
    return zl::zlbase::ZLResult_Success;
}

int32_t ZLDcbGetItemStatus(int32_t boxnum, unsigned char *status)
{
    auto devices_config = CDeviceManager::Instance().GetDevicesConfig();
    auto devices = CDeviceManager::Instance().GetDoorControlBoardList();

    if(devices_config.empty())
    {
        return zl::zlbase::ZLResult_Unconnected;
    }

    int32_t index = boxnum;
    for (const auto &dc : devices_config)
    {
        if (index > dc.count)
        {
            index -= dc.count;
            continue;
        }

        auto device = devices[dc.number];
        if (device == nullptr)
        {
            return zl::zlbase::ZLResult_Unconnected;
        }
        return device->GetItemStatus(index, *status);
    }
}